﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DevelopTool.Bll.AssemblyyBlls;
using DevelopTool.Common;
using DevelopTool.Forms.BaseForms;
using DevelopTool.Forms.CommonControls;
using DevelopTool.Forms.LodingForm;
using DevelopTool.Model;
using DevelopTool.Model.AssemblyyModels;
using DevelopTool.Model.CommonModels;
using Sunny.UI;

namespace DevelopTool.Forms.ToolForms
{
    /// <summary>
    /// 程序集内容搜索
    /// </summary>
    public partial class SearchAssemblyForm : BaseUIPage
    {
        private string folderPath;

        /// <summary>
        /// 目录路径
        /// </summary>
        public string FolderPath
        {
            get
            {
                return this.folderPath;
            }
            set
            {
                this.folderPath = value;
            }
        }

        private AssemblyyBll assemblyyBll;

        /// <summary>
        /// 总任务开始时间
        /// </summary>
        private DateTime taskstartTime;


        /// <summary>
        /// 检测任务状态的计时器
        /// </summary>
        private Timer taskTimer;


        /// <summary>
        /// 当前任务开始时间
        /// </summary>
        private DateTime nowTaskStartTime;

        /// <summary>
        /// 结果
        /// </summary>
        private DataTable resultTable;


        /// <summary>
        /// DataGridView列信息集合
        /// </summary>
        private readonly List<DataGridColumn> dataGridColumns = new List<DataGridColumn>()
              {
                { new DataGridColumn("Id"){ColumnText="Id",Width=5,ColumnType = ColumnType.Hide}},
                { new DataGridColumn("Name"){ColumnText="程序集",Width=0,}},
                { new DataGridColumn("Class"){ColumnText="类名",Width=0,ColumnType = ColumnType.RowMain}},
                { new DataGridColumn("Content"){ColumnText="内容",Width=100,ColumnType = ColumnType.Hide}},
                { new DataGridColumn("Keyword"){ColumnText="关键字",Width=0}},
                { new DataGridColumn("MatchType"){ColumnText="匹配方式",Width=-1}},
                 { new DataGridColumn("MD5"){ColumnText="MD5值",Width=-1,ColumnType = ColumnType.Hide}},
                { new DataGridColumn("Path"){ColumnText="路径",Width=-1}},
              };

        public SearchAssemblyForm()
        {
            InitializeComponent();
        }

        private void SearchAssemblyForm_Load(object sender,EventArgs e)
        {
            this.Disposed += this.SearchAssemblyForm_Disposed;

            //初始化任务报告DataTable
            resultTable = new DataTable("ResultTable");
            resultTable.Columns.Add("Id",typeof(int));
            resultTable.Columns.Add("Name",typeof(string));
            resultTable.Columns.Add("Class",typeof(string));
            resultTable.Columns.Add("Keyword",typeof(string));
            resultTable.Columns.Add("MatchType",typeof(string));
            resultTable.Columns.Add("Content",typeof(string));
            resultTable.Columns.Add("MD5",typeof(string));
            resultTable.Columns.Add("Path",typeof(string));

            this.dataDisplayControl.BindData(resultTable,this.dataGridColumns);

            this.dataDisplayControl.BindContextMenuStrip(this.ContextMenuStripDgv);//绑定右键菜单

            if(!string.IsNullOrEmpty(this.folderPath))
            {
                this.txtFolderPath.Text = this.folderPath;
            }
            else
            {
                //从配置文件获取上一次的路径
                this.txtFolderPath.Text = Setting.Tool.SearchAssembly_FolderPath;
            }
        }



        private void btnSearch_Click(object sender,EventArgs e)
        {
            if(this.backgroundWorker.IsBusy)
            {
                this.assemblyyBll.StopDecompile();
                this.btnSearch.Text = "搜索";
                this.btnSearch.Symbol = 61515;
                this.btnSearch.Enabled = false;
                backgroundWorker.CancelAsync();//停止后台任务
            }
            else
            {
                if(string.IsNullOrEmpty(this.txtFolderPath.Text))
                {
                    this.ShowWarningNotifier("请选择程序集目录");
                    return;
                }
                if(!Directory.Exists(this.txtFolderPath.Text))
                {
                    this.ShowWarningNotifier("程序集目录不存在");
                    return;
                }
                if(string.IsNullOrEmpty(this.txtKeyword.Text))
                {
                    this.ShowWarningNotifier("请输入搜索关键字");
                    return;
                }

                //获取目录中的所有程序集
                SearchOption searchOption = SearchOption.AllDirectories;//默认搜索子目录
                if(!this.chbContainSubFolder.Checked) searchOption = SearchOption.TopDirectoryOnly;

                List<string> assemblyFiles = new List<string>();
                LoadingHelper.ShowLoading("正在分析目录中的程序集",() =>
                {
                    assemblyFiles = Directory.GetFiles(this.txtFolderPath.Text,"*.*",searchOption).Where(it => (it.ToLower().EndsWith(".dll") || it.ToLower().EndsWith(".exe")) && AssemblyHelper.IsAssembly(it)).ToList();
                });

                if(assemblyFiles.Count <= 0)
                {
                    this.ShowWarningNotifier("目录中未找到有效的程序集");
                    return;
                }


                this.assemblyyBll = new AssemblyyBll();

                this.taskstartTime = DateTime.Now;

                resultTable.Clear();

                backgroundWorker.RunWorkerAsync(assemblyFiles);//开始后台任务          


                //创建并启动检测任务状态的计时器
                taskTimer = new Timer
                {
                    Interval = 100,
                    Enabled = true
                };
                taskTimer.Tick += TaskTimer_Tick;

                this.btnSearch.Text = "停止";
                this.btnSearch.Symbol = 61517;
            }
        }



        #region 后台任务

        /// <summary>
        /// 开始后台任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_DoWork(object sender,System.ComponentModel.DoWorkEventArgs e)
        {
            List<string> assemblyFiles = e.Argument as List<string>;//程序集集合
            List<string> keywordList = null;

            int taskexecutedNum = 0;//已执行完成任务数

            foreach(string assemblyFile in assemblyFiles)
            {
                if(this.backgroundWorker.CancellationPending) break;

                this.nowTaskStartTime = DateTime.Now;//当前任务开始时间

                this.Invoke(new Action(() =>
                {
                    txtNowAssemblyName.Text = assemblyFile;//当前任务名
                    keywordList = this.txtKeyword.Text.Split(new char[] { ';','；' },StringSplitOptions.RemoveEmptyEntries).ToList();//关键字分隔
                }));

                var result = assemblyyBll.SearchAssemblyContent(assemblyFile,keywordList,this.chbIgnoreCase.Checked);//搜索内容，这是核心

                backgroundWorker.ReportProgress(0,result);//报告状态，展示结果
                taskexecutedNum++;

                this.BeginInvoke(new Action(() =>
                {
                    lblTaskCount.Text = assemblyFiles.Count + "/" + taskexecutedNum;//剩余任务数
                }));
            }

        }



        /// <summary>
        /// 线程报告进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_ProgressChanged(object sender,System.ComponentModel.ProgressChangedEventArgs e)
        {
            var list = e.UserState as List<Tuple<string,Assemblyy>>;
            foreach(var item in list)
            {
                if(item == null) continue;

                foreach(var content in item.Item2.Contents)
                {
                    DataRow dataRow = resultTable.NewRow();
                    dataRow["Id"] = item.Item2.Id;
                    dataRow["Name"] = item.Item2.Name;
                    dataRow["Class"] = content.TypeName;
                    dataRow["Keyword"] = item.Item1;
                    dataRow["MatchType"] = item.Item2.MatchType;
                    dataRow["Content"] = content.Text;
                    dataRow["MD5"] = item.Item2.Sign;
                    dataRow["Path"] = item.Item2.Path;
                    resultTable.Rows.Add(dataRow);
                }
            }
        }



        /// <summary>
        /// 线程完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_RunWorkerCompleted(object sender,System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            this.btnSearch.Enabled = true;

            //停止计时器
            this.taskTimer.Stop();
            this.taskTimer.Dispose();

            txtNowAssemblyName.Text = string.Empty;
            lblTime.Text = string.Empty;


            //手动停止时，不推送消息
            if(!backgroundWorker.CancellationPending)
            {
                if(Setting.System.SendMsgModule.Contains("SearchAssemblyComplete"))
                    FeiShuMsgHelper.SendCardMsgAsync($"结果：{resultTable.Rows.Count}",$"程序集搜索完成");
            }
        }

        #endregion

        /// <summary>
        /// 检测任务状态的计时器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void TaskTimer_Tick(object sender,EventArgs e)
        {
            //当前任务耗时
            TimeSpan timeSpan = new TimeSpan(nowTaskStartTime.Ticks).Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration();
            lblTime.Text = timeSpan.TotalSeconds.ToDouble(1).ToString();

            //总任务耗时
            TimeSpan timeSpanTotal = new TimeSpan(taskstartTime.Ticks).Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration();
            lblTotalTime.Text = timeSpanTotal.TotalSeconds.ToDouble(1).ToString();

        }

        /// <summary>
        /// 选择程序集目录
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtFolderPath_ButtonClick(object sender,EventArgs e)
        {
            string dir = txtFolderPath.Text;
            if(Dialogs.SelectDirEx("请选择程序集目录",ref dir))
            {
                this.txtFolderPath.Text = dir;
            }
        }


        private void txtFolderPath_TextChanged(object sender,EventArgs e)
        {
            Setting.Tool.SearchAssembly_FolderPath = this.txtFolderPath.Text;
        }

        private void dataDisplayControl_DataGridViewCellClick(DataGridViewEventArgs dataGridViewEventArgs)
        {
            if(dataGridViewEventArgs.MouseButton == MouseButtons.Right)//判断点的是不是右键
            {
                ContextMenuStripDgv.Tag = new Assemblyy()
                {
                    Id = dataGridViewEventArgs.Row.Cells["Id"].Value.ToInt(),
                    Name = dataGridViewEventArgs.Row.Cells["Name"].Value.ToString(),
                    Sign = dataGridViewEventArgs.Row.Cells["MD5"].Value.ToString(),
                    Path = dataGridViewEventArgs.Row.Cells["Path"].Value.ToString(),
                    MatchType = dataGridViewEventArgs.Row.Cells["MatchType"].Value.ToString(),
                    Contents = new List<AssemblyyContent>() { new AssemblyyContent { TypeName = dataGridViewEventArgs.Row.Cells["Class"].Value.ToString(),Text = dataGridViewEventArgs.Row.Cells["Content"].Value.ToString() } }
                };
            }
            else if(dataGridViewEventArgs.MouseButton == MouseButtons.Left)//判断点的是不是左键
            {
                string name = dataGridViewEventArgs.Row.Cells["Name"].Value.ToString();
                string content = dataGridViewEventArgs.Row.Cells["Content"].Value.ToString();
                string className = dataGridViewEventArgs.Row.Cells["Class"].Value.ToString();
                string MD5 = dataGridViewEventArgs.Row.Cells["MD5"].Value.ToString();
                string keyword = dataGridViewEventArgs.Row.Cells["Keyword"].Value.ToString();

                if(!string.IsNullOrEmpty(className))
                    className = "-" + className;

                string tagStr = name + className + keyword + MD5;


                if(this.codeEditorControl.Tag != null && this.codeEditorControl.Tag.ToString() == tagStr)
                {
                    this.codeEditorControl.TextPosition(keyword,ignoreCase: this.chbIgnoreCase.Checked);
                }
                else
                {
                    this.codeEditorControl.ContentText = content;
                    this.codeEditorControl.PanelTitle = name + className;
                    this.codeEditorControl.Tag = tagStr;
                }
            }
        }


        private void 在ILSpy中打开程序集ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            Assemblyy assemblyy = item.Owner.Tag as Assemblyy;
            
            UITabControl parentTabControl = this.GetParentControl<UITabControl>();
            if(parentTabControl != null)
            {
                ILSpyForm iLSpyForm = new ILSpyForm();
                iLSpyForm.AssemblyPath = assemblyy.Path;

                string className = assemblyy.Contents[0].TypeName;

                if(!string.IsNullOrEmpty(className))
                    iLSpyForm.NavigateTo = $"/navigateTo:T:{className}";

                TabControlHelper.AddPageToTabControl(parentTabControl,iLSpyForm,Path.GetFileName(assemblyy.Path),true,$"{assemblyy.Path}-{className}");
            }
        }

        private void 打开所在的目录ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            Assemblyy assemblyy = item.Owner.Tag as Assemblyy;
            Dialogs.OpenDir(assemblyy.Path);
        }


        private void 从缓存中删除选中的ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            List<int> ids = new List<int>();
            foreach(DataGridViewCell cell in this.dataDisplayControl.DataGridView.SelectedCells)
            {
                var row = this.dataDisplayControl.DataGridView.Rows[cell.RowIndex];//当前选中的行
                int id = row.Cells["Id"].Value.ToInt();//取得列名

                if(id <= 0) continue;
                ids.Add(id);
            }
            if(this.assemblyyBll.Delete(ids))
            {
                this.ShowSuccessNotifier("缓存删除成功");
            }
            else
            {
                this.ShowErrorNotifier("缓存删除失败");
            }
        }


        private void txtKeyword_ButtonClick(object sender,EventArgs e)
        {
            this.txtKeyword.Text = string.Empty;
        }


        private void SearchAssemblyForm_Disposed(object sender,EventArgs e)
        {
            try
            {
                this.backgroundWorker.CancelAsync();
                this.backgroundWorker.Dispose();
            }
            catch(Exception ex)
            {
                LogHelper.WriteErrLog(ex);
            }
        }
    }
}
